package pa3;

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;

public class LoggerImpl extends UnicastRemoteObject implements Logger, Runnable{

	private static final long serialVersionUID = -4333457720871782557L;
	private final int MEASUREMENT_TIME = 120000;

	private HashMap<String, Boolean> registeredHosts;
	
	private Timer timer = new Timer();
	private boolean timerStarted = false;
	private boolean measurementStopped = false;
	
	private int crashes;
	private int falsePositives;
	
	private int messageCount = 0;
	
	protected LoggerImpl() throws RemoteException {
		super();
		registeredHosts = new HashMap<String, Boolean>();
	}

	@Override
	public void run() {
		try {
			//the commented block will be needed when testing the whole thing with mor than one computers
			/*
			Properties systemProperties = 
			      new Properties( System.getProperties() );
			systemProperties.put("java.rmi.server.hostname","10.0.0.3");
			systemProperties.put("java.security.policy", "policy");
			System.setProperties(systemProperties);
			if(System.getSecurityManager() == null){
				System.setSecurityManager(new RMISecurityManager());
			}
			*/
			Registry registry = LocateRegistry.getRegistry();
//			Registry registry = LocateRegistry.createRegistry(Registry.REGISTRY_PORT);			
			registry.rebind(Logger.SERVICENAME, this);
			System.out.println("Bound Logger in local registry.");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public synchronized void register(String hostName) throws RemoteException {
		if(!registeredHosts.containsKey(hostName)){
			registeredHosts.put(hostName, false);
			System.out.println("[LOGGER]"+hostName+" registered with logger");
		}
	}

	@Override
	public synchronized void reportCrashedHost(String crashedHost) throws RemoteException {
		if(!registeredHosts.get(crashedHost)){
			falsePositives++;		
			System.err.println("FALSE POSITIVE DETECTED - "+ crashedHost +":"+ System.currentTimeMillis());
		}
		
		System.out.println("[LOGGER]"+crashedHost+" reported to be crashed");
	}

	@Override
	public synchronized void logCrash(String crashedHost) throws RemoteException {
		registeredHosts.put(crashedHost, true);
		crashes++;
		System.err.println("[LOGGER]"+crashedHost+" crashed");
	}

	@Override
	public synchronized void logRecovery(String recoveredHost) throws RemoteException {
		registeredHosts.put(recoveredHost, false);
		System.out.println("*[LOGGER]"+recoveredHost+" recovered from crash");
	}

	@Override
	public float getFalsePositiveRate() throws RemoteException {
		System.out.println(falsePositives +"/"+crashes);
		return falsePositives / crashes;
	}

	@Override
	public synchronized void incrementMessageCount() throws RemoteException {
		if(!timerStarted){
			timer.schedule(new StopMeasurement(), MEASUREMENT_TIME);
			timerStarted = true;
		}
		
		if(!measurementStopped){
			messageCount++;
		}
	}
	
	class StopMeasurement extends TimerTask{
		public StopMeasurement(){
			
		}
		@Override
		public void run() {
			measurementStopped = true;
			System.out.println("[MESSAGES AFTER 120 SECONDS]"+messageCount);
			System.out.println("[FALSE POSITIVE RATE]"+falsePositives);
			timer.cancel();
		}
	}

}
